{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "c6q8_gU4RClu"
   },
   "source": [
    "# Exploring the MNIST Digits Dataset"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "gRRWy7XpRHbq"
   },
   "source": [
    "## Importing Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "X2D5_56r3cSM",
    "outputId": "a2ed720b-afc4-495b-c57a-54f10eda2bcb"
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "from tensorflow import keras\n",
    "import tensorflow as tf\n",
    "\n",
    "(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Z2FU9cyERJZ3"
   },
   "source": [
    "## Exploring Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "boaW64qdDryf",
    "outputId": "a15994bc-87a4-42c8-f105-07b8256952ba"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "x_train shape: (60000, 28, 28)\n",
      "y_train shape: (60000,)\n",
      "x_test shape: (10000, 28, 28)\n",
      "y_test shape: (10000,)\n"
     ]
    }
   ],
   "source": [
    "# check shape of the data\n",
    "\n",
    "print(f\"x_train shape: {x_train.shape}\")\n",
    "print(f\"y_train shape: {y_train.shape}\")\n",
    "\n",
    "print(f\"x_test shape: {x_test.shape}\")\n",
    "print(f\"y_test shape: {y_test.shape}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 282
    },
    "id": "F5DH7XCyDx6p",
    "outputId": "8b30fe19-cd81-4773-a47c-2592922866f5"
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPsAAAD4CAYAAAAq5pAIAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8rg+JYAAAACXBIWXMAAAsTAAALEwEAmpwYAAAN8klEQVR4nO3df6jVdZ7H8ddrbfojxzI39iZOrWOEUdE6i9nSyjYRTj8o7FYMIzQ0JDl/JDSwyIb7xxSLIVu6rBSDDtXYMus0UJHFMNVm5S6BdDMrs21qoxjlphtmmv1a9b1/3K9xp+75nOs53/PD+34+4HDO+b7P93zffPHl99f53o8jQgAmvj/rdQMAuoOwA0kQdiAJwg4kQdiBJE7o5sJsc+of6LCI8FjT29qy277C9lu237F9ezvfBaCz3Op1dtuTJP1B0gJJOyW9JGlRROwozMOWHeiwTmzZ50l6JyLejYgvJf1G0sI2vg9AB7UT9hmS/jjq/c5q2p+wvcT2kO2hNpYFoE0dP0EXEeskrZPYjQd6qZ0t+y5JZ4x6/51qGoA+1E7YX5J0tu3v2j5R0o8kbaynLQB1a3k3PiIO2V4q6SlJkyQ9EBFv1NYZgFq1fOmtpYVxzA50XEd+VAPg+EHYgSQIO5AEYQeSIOxAEoQdSIKwA0kQdiAJwg4kQdiBJAg7kARhB5Ig7EAShB1IgrADSRB2IAnCDiRB2IEkCDuQBGEHkiDsQBKEHUiCsANJEHYgCcIOJEHYgSQIO5AEYQeSIOxAEi0P2Yzjw6RJk4r1U045paPLX7p0acPaSSedVJx39uzZxfqtt95arN9zzz0Na4sWLSrO+/nnnxfrK1euLNbvvPPOYr0X2gq77fckHZB0WNKhiJhbR1MA6lfHlv3SiPiwhu8B0EEcswNJtBv2kPS07ZdtLxnrA7aX2B6yPdTmsgC0od3d+PkRscv2X0h6xvZ/R8Tm0R+IiHWS1kmS7WhzeQBa1NaWPSJ2Vc97JD0maV4dTQGoX8thtz3Z9pSjryX9QNL2uhoDUK92duMHJD1m++j3/HtE/L6WriaYM888s1g/8cQTi/WLL764WJ8/f37D2tSpU4vzXn/99cV6L+3cubNYX7NmTbE+ODjYsHbgwIHivK+++mqx/sILLxTr/ajlsEfEu5L+qsZeAHQQl96AJAg7kARhB5Ig7EAShB1IwhHd+1HbRP0F3Zw5c4r1TZs2Feudvs20Xx05cqRYv/nmm4v1Tz75pOVlDw8PF+sfffRRsf7WW2+1vOxOiwiPNZ0tO5AEYQeSIOxAEoQdSIKwA0kQdiAJwg4kwXX2GkybNq1Y37JlS7E+a9asOtupVbPe9+3bV6xfeumlDWtffvllcd6svz9oF9fZgeQIO5AEYQeSIOxAEoQdSIKwA0kQdiAJhmyuwd69e4v1ZcuWFetXX311sf7KK68U683+pHLJtm3bivUFCxYU6wcPHizWzzvvvIa12267rTgv6sWWHUiCsANJEHYgCcIOJEHYgSQIO5AEYQeS4H72PnDyyScX682GF167dm3D2uLFi4vz3njjjcX6hg0binX0n5bvZ7f9gO09trePmjbN9jO2366eT62zWQD1G89u/K8kXfG1abdLejYizpb0bPUeQB9rGvaI2Czp678HXShpffV6vaRr620LQN1a/W38QEQcHSzrA0kDjT5oe4mkJS0uB0BN2r4RJiKidOItItZJWidxgg7opVYvve22PV2Squc99bUEoBNaDftGSTdVr2+S9Hg97QDolKa78bY3SPq+pNNs75T0c0krJf3W9mJJ70v6YSebnOj279/f1vwff/xxy/PecsstxfrDDz9crDcbYx39o2nYI2JRg9JlNfcCoIP4uSyQBGEHkiDsQBKEHUiCsANJcIvrBDB58uSGtSeeeKI47yWXXFKsX3nllcX6008/Xayj+xiyGUiOsANJEHYgCcIOJEHYgSQIO5AEYQeS4Dr7BHfWWWcV61u3bi3W9+3bV6w/99xzxfrQ0FDD2n333Vect5v/NicSrrMDyRF2IAnCDiRB2IEkCDuQBGEHkiDsQBJcZ09ucHCwWH/wwQeL9SlTprS87OXLlxfrDz30ULE+PDxcrGfFdXYgOcIOJEHYgSQIO5AEYQeSIOxAEoQdSILr7Cg6//zzi/XVq1cX65dd1vpgv2vXri3WV6xYUazv2rWr5WUfz1q+zm77Adt7bG8fNe0O27tsb6seV9XZLID6jWc3/leSrhhj+r9ExJzq8bt62wJQt6Zhj4jNkvZ2oRcAHdTOCbqltl+rdvNPbfQh20tsD9lu/MfIAHRcq2H/haSzJM2RNCxpVaMPRsS6iJgbEXNbXBaAGrQU9ojYHRGHI+KIpF9KmldvWwDq1lLYbU8f9XZQ0vZGnwXQH5peZ7e9QdL3JZ0mabekn1fv50gKSe9J+mlENL25mOvsE8/UqVOL9WuuuaZhrdm98vaYl4u/smnTpmJ9wYIFxfpE1eg6+wnjmHHRGJPvb7sjAF3Fz2WBJAg7kARhB5Ig7EAShB1Igltc0TNffPFFsX7CCeWLRYcOHSrWL7/88oa1559/vjjv8Yw/JQ0kR9iBJAg7kARhB5Ig7EAShB1IgrADSTS96w25XXDBBcX6DTfcUKxfeOGFDWvNrqM3s2PHjmJ98+bNbX3/RMOWHUiCsANJEHYgCcIOJEHYgSQIO5AEYQeS4Dr7BDd79uxifenSpcX6ddddV6yffvrpx9zTeB0+fLhYHx4u//XyI0eO1NnOcY8tO5AEYQeSIOxAEoQdSIKwA0kQdiAJwg4kwXX240Cza9mLFo010O6IZtfRZ86c2UpLtRgaGirWV6xYUaxv3LixznYmvKZbdttn2H7O9g7bb9i+rZo+zfYztt+unk/tfLsAWjWe3fhDkv4+Is6V9DeSbrV9rqTbJT0bEWdLerZ6D6BPNQ17RAxHxNbq9QFJb0qaIWmhpPXVx9ZLurZDPQKowTEds9ueKel7krZIGoiIoz9O/kDSQIN5lkha0kaPAGow7rPxtr8t6RFJP4uI/aNrMTI65JiDNkbEuoiYGxFz2+oUQFvGFXbb39JI0H8dEY9Wk3fbnl7Vp0va05kWAdSh6W68bUu6X9KbEbF6VGmjpJskrayeH+9IhxPAwMCYRzhfOffcc4v1e++9t1g/55xzjrmnumzZsqVYv/vuuxvWHn+8/E+GW1TrNZ5j9r+V9GNJr9veVk1brpGQ/9b2YknvS/phRzoEUIumYY+I/5I05uDuki6rtx0AncLPZYEkCDuQBGEHkiDsQBKEHUiCW1zHadq0aQ1ra9euLc47Z86cYn3WrFmttFSLF198sVhftWpVsf7UU08V65999tkx94TOYMsOJEHYgSQIO5AEYQeSIOxAEoQdSIKwA0mkuc5+0UUXFevLli0r1ufNm9ewNmPGjJZ6qsunn37asLZmzZrivHfddVexfvDgwZZ6Qv9hyw4kQdiBJAg7kARhB5Ig7EAShB1IgrADSaS5zj44ONhWvR07duwo1p988sli/dChQ8V66Z7zffv2FedFHmzZgSQIO5AEYQeSIOxAEoQdSIKwA0kQdiAJR0T5A/YZkh6SNCApJK2LiH+1fYekWyT9b/XR5RHxuybfVV4YgLZFxJijLo8n7NMlTY+IrbanSHpZ0rUaGY/9k4i4Z7xNEHag8xqFfTzjsw9LGq5eH7D9pqTe/mkWAMfsmI7Zbc+U9D1JW6pJS22/ZvsB26c2mGeJ7SHbQ+21CqAdTXfjv/qg/W1JL0haERGP2h6Q9KFGjuP/SSO7+jc3+Q5244EOa/mYXZJsf0vSk5KeiojVY9RnSnoyIs5v8j2EHeiwRmFvuhtv25Lul/Tm6KBXJ+6OGpS0vd0mAXTOeM7Gz5f0n5Jel3Skmrxc0iJJczSyG/+epJ9WJ/NK38WWHeiwtnbj60LYgc5reTcewMRA2IEkCDuQBGEHkiDsQBKEHUiCsANJEHYgCcIOJEHYgSQIO5AEYQeSIOxAEoQdSKLbQzZ/KOn9Ue9Pq6b1o37trV/7kuitVXX29peNCl29n/0bC7eHImJuzxoo6Nfe+rUvid5a1a3e2I0HkiDsQBK9Dvu6Hi+/pF9769e+JHprVVd66+kxO4Du6fWWHUCXEHYgiZ6E3fYVtt+y/Y7t23vRQyO237P9uu1tvR6frhpDb4/t7aOmTbP9jO23q+cxx9jrUW932N5Vrbtttq/qUW9n2H7O9g7bb9i+rZre03VX6Ksr663rx+y2J0n6g6QFknZKeknSoojY0dVGGrD9nqS5EdHzH2DY/jtJn0h66OjQWrb/WdLeiFhZ/Ud5akT8Q5/0doeOcRjvDvXWaJjxn6iH667O4c9b0Yst+zxJ70TEuxHxpaTfSFrYgz76XkRslrT3a5MXSlpfvV6vkX8sXdegt74QEcMRsbV6fUDS0WHGe7ruCn11RS/CPkPSH0e936n+Gu89JD1t+2XbS3rdzBgGRg2z9YGkgV42M4amw3h309eGGe+bddfK8Oft4gTdN82PiL+WdKWkW6vd1b4UI8dg/XTt9BeSztLIGIDDklb1splqmPFHJP0sIvaPrvVy3Y3RV1fWWy/CvkvSGaPef6ea1hciYlf1vEfSYxo57Ognu4+OoFs97+lxP1+JiN0RcTgijkj6pXq47qphxh+R9OuIeLSa3PN1N1Zf3VpvvQj7S5LOtv1d2ydK+pGkjT3o4xtsT65OnMj2ZEk/UP8NRb1R0k3V65skPd7DXv5Evwzj3WiYcfV43fV8+POI6PpD0lUaOSP/P5L+sRc9NOhrlqRXq8cbve5N0gaN7Nb9n0bObSyW9OeSnpX0tqT/kDStj3r7N40M7f2aRoI1vUe9zdfILvprkrZVj6t6ve4KfXVlvfFzWSAJTtABSRB2IAnCDiRB2IEkCDuQBGEHkiDsQBL/DyJ7caZa7LphAAAAAElFTkSuQmCC",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "correct number: 5\n"
     ]
    }
   ],
   "source": [
    "# visualize single data instances\n",
    "\n",
    "img_no = 0 #change the number to display other examples\n",
    "\n",
    "first_number = x_train[img_no]\n",
    "plt.imshow(first_number, cmap='gray') # visualize the numbers in gray mode\n",
    "plt.show()\n",
    "print(f\"correct number: {y_train[img_no]}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "jygNEJ4dRm3o"
   },
   "source": [
    "## Preparing Data & Splitting"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "7B7d7i3uThoq",
    "outputId": "20ca74ea-0844-4a93-c7bd-8e48d454d65d"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train X shape: (60000, 28, 28, 1)\n",
      "test X shape: (10000, 28, 28, 1)\n"
     ]
    }
   ],
   "source": [
    "# reshaping the data\n",
    "# reshaping pixels in a 28x28px image with greyscale, canal = 1. This is needed for the Keras API\n",
    "x_train = x_train.reshape(-1,28,28,1)\n",
    "x_test = x_test.reshape(-1,28,28,1)\n",
    "\n",
    "# normalizing the data\n",
    "# each pixel has a value between 0-255. Here we divide by 255, to get values from 0-1\n",
    "x_train = x_train / 255\n",
    "x_test = x_test / 255\n",
    "\n",
    "print(f\"train X shape: {x_train.shape}\")\n",
    "print(f\"test X shape: {x_test.shape}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "S6tti0-ke81d"
   },
   "outputs": [],
   "source": [
    "# new functions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "dOtAx2G9hD2W"
   },
   "source": [
    "## Model Building"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "DI795SvBhGPW",
    "outputId": "b66e6a8c-4dba-4f0d-8675-f5bd9f3ff594"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"sequential\"\n",
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "conv2d (Conv2D)              (None, 26, 26, 64)        640       \n",
      "_________________________________________________________________\n",
      "max_pooling2d (MaxPooling2D) (None, 13, 13, 64)        0         \n",
      "_________________________________________________________________\n",
      "conv2d_1 (Conv2D)            (None, 11, 11, 64)        36928     \n",
      "_________________________________________________________________\n",
      "max_pooling2d_1 (MaxPooling2 (None, 5, 5, 64)          0         \n",
      "_________________________________________________________________\n",
      "conv2d_2 (Conv2D)            (None, 3, 3, 64)          36928     \n",
      "_________________________________________________________________\n",
      "max_pooling2d_2 (MaxPooling2 (None, 1, 1, 64)          0         \n",
      "_________________________________________________________________\n",
      "flatten (Flatten)            (None, 64)                0         \n",
      "_________________________________________________________________\n",
      "dense (Dense)                (None, 64)                4160      \n",
      "_________________________________________________________________\n",
      "dense_1 (Dense)              (None, 32)                2080      \n",
      "_________________________________________________________________\n",
      "dense_2 (Dense)              (None, 10)                330       \n",
      "=================================================================\n",
      "Total params: 81,066\n",
      "Trainable params: 81,066\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "model = keras.models.Sequential()\n",
    "model.add(keras.layers.Conv2D(64, (3, 3), activation='relu', input_shape=(28,28,1)))\n",
    "model.add(keras.layers.MaxPool2D(2, 2))\n",
    "\n",
    "model.add(keras.layers.Conv2D(64, (3, 3), activation='relu'))\n",
    "model.add(keras.layers.MaxPool2D(2, 2))\n",
    "\n",
    "model.add(keras.layers.Conv2D(64, (3, 3), activation='relu'))\n",
    "model.add(keras.layers.MaxPool2D(2, 2))\n",
    "\n",
    "model.add(keras.layers.Flatten())\n",
    "model.add(keras.layers.Dense(64, activation='relu'))\n",
    "\n",
    "model.add(keras.layers.Dense(32, activation='relu'))\n",
    "\n",
    "model.add(keras.layers.Dense(10, activation='softmax')) #output are 10 classes, numbers from 0-9\n",
    "\n",
    "#show model summary - how it looks\n",
    "model.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "id": "UpdaKIGoxHiC"
   },
   "outputs": [],
   "source": [
    "#compile the model - we want to have a multiple outcome\n",
    "model.compile(optimizer=\"adam\",\n",
    "              loss=\"sparse_categorical_crossentropy\",\n",
    "              metrics=['accuracy'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "qHaJJk-gxJLq",
    "outputId": "f2d4c7d6-b164-4c54-9ab7-a648169e345b"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1875/1875 [==============================] - 461s 245ms/step - loss: 0.2054 - accuracy: 0.9356\n"
     ]
    }
   ],
   "source": [
    "#fit the model and return the history while training\n",
    "history = model.fit(\n",
    "  x=x_train,\n",
    "  y=y_train,\n",
    "  epochs=1\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "rvcNPDwWQhib"
   },
   "source": [
    "## Model Evaluation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "INFO:tensorflow:Assets written to: models/detect-digits/assets\n"
     ]
    }
   ],
   "source": [
    "keras.models.save_model(model,\"models/detect-digits\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "from minio import Minio\n",
    "import os\n",
    "\n",
    "minio_client = Minio(\n",
    "        \"100.65.11.110:9000\",\n",
    "        access_key=\"minio\",\n",
    "        secret_key=\"minio123\",\n",
    "        secure=False\n",
    "    )\n",
    "minio_bucket = \"mlpipeline\"\n",
    "\n",
    "\n",
    "import glob\n",
    "\n",
    "def upload_local_directory_to_minio(local_path, bucket_name, minio_path):\n",
    "    assert os.path.isdir(local_path)\n",
    "\n",
    "    for local_file in glob.glob(local_path + '/**'):\n",
    "        local_file = local_file.replace(os.sep, \"/\") # Replace \\ with / on Windows\n",
    "        if not os.path.isfile(local_file):\n",
    "            upload_local_directory_to_minio(\n",
    "                local_file, bucket_name, minio_path + \"/\" + os.path.basename(local_file))\n",
    "        else:\n",
    "            remote_path = os.path.join(\n",
    "                minio_path, local_file[1 + len(local_path):])\n",
    "            remote_path = remote_path.replace(\n",
    "                os.sep, \"/\")  # Replace \\ with / on Windows\n",
    "            minio_client.fput_object(bucket_name, remote_path, local_file)\n",
    "            \n",
    "upload_local_directory_to_minio(\"models/detect-digits\",minio_bucket,\"/models/detect-digits\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "metadata": {
    "id": "ZsrEjddE1bbf"
   },
   "outputs": [],
   "source": [
    "#load model if already trained\n",
    "model = keras.models.load_model(\"detect-digits.h5\")\n",
    "#keras.models.save_model(model,\"detect-digits.h5\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "bypXyDxMQj0u",
    "outputId": "2f679161-a921-4abd-bac5-b2436e9bcbe8"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "313/313 [==============================] - 21s 66ms/step - loss: 0.0853 - accuracy: 0.9743\n"
     ]
    }
   ],
   "source": [
    "# Test the model against the test dataset\n",
    "# Returns the loss value & metrics values for the model in test mode.\n",
    "model_loss, model_accuracy = model.evaluate(x=x_test,y=y_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 297
    },
    "id": "wVohS46mxRDe",
    "outputId": "b64db43b-07f7-4b2e-e801-e7791484a6e7"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Text(0.5, 15.0, 'Predicted'), Text(33.0, 0.5, 'Actual')]"
      ]
     },
     "execution_count": 91,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAEGCAYAAAB1iW6ZAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8rg+JYAAAACXBIWXMAAAsTAAALEwEAmpwYAABD2klEQVR4nO3dd3wU1drA8d+zSSCFEpAOCiLYUUoooqII0gQpKhawXRVFLuq1dy5YXvSqoNd7pQgqLTQp0pEmRUqAhN4C0gmhBUKoSc77x05iwAQ2yc5kM/f58pkPm9md88yZ3T2ZnDlzHjHGoJRSqvDzFPQOKKWU8g9t0JVSyiW0QVdKKZfQBl0ppVxCG3SllHKJ4ILegZycnvCpY8Nvij/yH6dCqUIkJMi5r8f5tFRH4ogjUbycHD+Xem5fvqt2/vAOn3c5pEx1Jw+lzwK2QVdKKUelpxX0HuSbNuhKKQVg0gt6D/JNG3SllAJI1wZdKaVcwegZulJKuYRDF6btpA26UkqBKy6KFrpx6COXbOSB/pPp1G8SIxZvvOC5YYs2UPudnziWcgaAabE7eOjrX3iw/2Se+G46Ww4c9cs+tGxxNxvWL2TzxsW8+UYPv5SZE4/HQ8yKWUye+JOtcZyqU5UqlZgzexxr18xnTdw8ev79Gdtigb31qlKlIjNnjmb16jmsWvUrPXo8DcB7773C9u3LWbZsOsuWTadly6Z+juvcMdy2dRmxq+ewMmY2y5ZOty0OOPu9ypZJ930JUIXqDD0+4RgTYrYx4sX7CAny0OOHOTS5vgpXlSlBQlIKS7ftp2JkRObrK5cuxpBuLSkRVpTFW/by0YSljOhxX772wePx8M3Xn9CqzaPs3XuAZUunM2XqbDZt2pbf6mXrpZ7PsnnzNkoUL25L+eBsnVJTU3njzd7Exq2nWLEIViyfyZy5C22JZXe9UlPTePvtj4mz6vL771OZO3cxAP/+9xD69x/klzh/jevcMQRofu9DHDlyzJayMzj9vcqWCy6K2naGLiLXi8hbIvKNtbwlIjfkp8wdh45T68oyhBUJJjjIQ72ryzN3w24AvpgWwyut613w+tpVy1EirCgAt1xVloMnUvITHoAG9euwfftO/vhjN+fPn2fs2Mnc365lvsvNTuXKFWnTuhlDh0bbUn4GJ+uUkJBIbNx6AE6eTGHz5m1UrlTBllh21yshIZG4C+oST6VK5f1W/qXiOnUMneLkZzAnxqT7vAQqWxp0EXkLGI33xrQV1iJAtIi8nddya5SPZPUfiSSlnOH0uVQWb9nHweMpzN+4m7IlwrmuYukct50Ys407rq2S19CZKlWuwJ69+zN/3rvvAJVs+jJ99WVv3n7nY9JtPnNwsk5ZVa1ahdq33szyFbG2lO9kva66qgq1a99ETEwcAC+88AQrVsxkwIB/ERlZwpaYYP8xNMYwY3o0y5fN4NlnutgSAwruM3iB9HTflwBl1xn6M0B9Y0xfY8wIa+kLNLCey5aIdBORlSKycsjsFX95vnq5SJ6+62a6D/2VHj/8ynWVSnEuNY0h89fx4r21c9yZmO0HmLQynpdb1c1/zRxyX5vmJCYeZnXsuoLeFVtERIQzdsxgXn29F8nJJwt6d/IlIiKc6OgBvPFGH5KTTzJ48AhuvLEJDRu2JiEhkb59P7Atrt3H8O6mHWnQsBVt23Wle/enuOOOhrbECQhp531fApRdDXo6UCmb9RWt57JljBlkjIkyxkQ906JBtq/pWL8m0T3bMfT51hQPK8o15SPZd+wknb/+hdafjSfxxCke/fdUDiefBmDrgaP0nvA7/R9vSmREaL4rtn9fAldW+bNqVSpXZP/+hHyXe7HGjaNo17YF8VuXMXLEf2na9HZ++vEbv8cB5+qUITg4mHFjBhMdPZFJk2bYFseJegUHBxMdPYAxYyYxefJMABITD5Oeno4xhqFDo4mKutWvMTPiOnIMreN16NARJk2eQf36te2J4/BnMFsuuChqV4P+CjBXRGaIyCBrmQnMBV7OT8FHT3ob6gNJJ5m3YRft6tZg/vsPM+OtB5nx1oOUKxFOdM+2lCkexoGkk7w2YgEfd76TqmVL5rtSADEr46hR42qqVbuSkJAQOnduz5Sps/1Sdlbvvd+XatWjqHFtI7p0fZH585fw5FMv+T0OOFenDIMHfcmmzfH0/9qei4YZnKjXgAGfs2VLPN98833mugoVymU+bt++JRs3bvFrTHDmGIaHh1GsWETm43ub38WGDf6vCzj/GcyWC7pcbBnlYoyZKSLX4u1iqWyt3gfEGGPyNdjztZELOH7qLMEeD+/c34gSYUVyfO2guWtJOnWWTycvAyDY42HU39vmJzxpaWm8/Mr7TJ82iiCPhx9/GsPGjVvzVWZBc7JOtzeuz+NdH2Ttuo2sjPF+YT/4oC8zZs7zeyy769W4cRRdujzAunWbWLbMO6SvV69/0bnz/dxyy40YY9i1ay89e77rt5jg3DEsX74s48cNASAoOIjRoycxe/YCv8bIEBDfqwA+8/aVBGqSaJ0+VxU0nT43fwrb9Lln187yeZeL3tJSp89VSqlAZdID92Knr7RBV0opCOi+cV9pg66UUuCKPnRt0JVSClwxOZc26EopBa44Qy90sy0qpZQt/DgOXUSGikiiiKzPsq60iPwqItus/0tZ68Wa7ypeRNaKSN0s2zxpvX6biDx52biBOmwxuEhlx3bs9P5FToUirNKdjsVS6mI6bDFnZ5aM9HmXQ2/vcsl4ItIEOAkMM8bcbK37HDhqjOlrzWlVyhjzloi0AXoCbYCGwNfGmIYiUhpYCUThPZyrgHrGmBynvtQzdKWUAr+eoRtjFgIXJ2BoD2QkNvgJ6JBl/TDjtQyIFJGKQEvgV2PMUasR/xVodam42oeulFJAbm5iF5FuQLcsqwYZYy43D0N5Y8wB63ECkDHXcmVgT5bX7bXW5bQ+R9qgK6UU5GocutV453kiHWOMERG/90ppl4tSSoETsy0etLpSsP5PtNbvA67M8roq1rqc1udIG3SllAInZlv8BcgYqfIkMDnL+ies0S6NgONW18wsoIWIlLJGxLSw1uVIu1yUUgrAjxOkiUg0cDdQRkT2Ar2AvsBYEXkG2AV0tl4+He8Il3jgFPA0gDHmqIh8BMRYr+tjjLlkpnvXnKH7I2P4+59+RZP7HqFD1xcy182at4j2XZ6n1h1tWL/pz+k8f1+xms5/60nHx7vT+W89Wb4q7i/l/f3Nf15QVl44mQnd4/EQs2IWkyf+dPkX54OTdXIq1uBBX7J/7xriYufaFqMgYm3buozY1XNYGTObZUun2xrLyc9FtvzY5WKMedQYU9EYE2KMqWKMGWKMOWKMaWaMqWmMaZ7ROFujW3oYY64xxtQyxqzMUs5QY0wNa/nhcnFd0aBnZAxv264rtW5tysMPd+CGG2rmupwObe5lwFcfX7CuRvWq9P/0A+rVvvmC9aUiS/DtZ/9k4vDv+OT913inzxcXPP/rgiWEh4flvjJZ+Ktevnqp57Ns3mxvlnUn6+RkrGHDxnJfW/tybhZULIDm9z5EVP0WNLqtjW0xnP6sZ8sFCS5c0aD7K2N4VO1alCxR/IJ111S7iqur/jW59A3X1qBc2SsAqHF1Vc6cPcu5c+cAOHXqNMPGTOD5Jx/JQ23+5GQm9MqVK9KmdTOGDo22pfwMTtbJyViLFi/n6LEkW8ouyFhOcfK9ypE26LknIk/7u8yCzhj+64LF3HhdDYoU8WZP+vfgYTz5SCdCQ/OXw9TJen31ZW/efudj0m3+sDpZp4L+XLiBMYYZ06NZvmwGzz5j318FAfFeaU7RPOmd0xMi0k1EVorIyvT0FCf3Kc/id+ziq/8O5cM3egKweet29uw7QPO7bi/gPfPdfW2ak5h4mNWx6wp6V1SAubtpRxo0bEXbdl3p3v0p7rijYUHvkn3SUn1fApQto1xEZG1OT/Hn3VF/kXWwfm7mcimojOEJiYd4+d2P+PSD17nKih+3YRMbNm+jxQNPkpaWxpFjx3nq72/y47ef57p8p+rVuHEU7dq2oHWrewgNLUqJEsX56cdvbElK7eR7FRCZ5Au5jON16NARJk2eQf36tVm8eLn/4wTCexXAXSm+susMvTzwBNAum+WIv4MVRMbwE8knefGNXrzywtPUveWmzPWPdGzL/F9GMvvnnxj23ZdUu7JynhpzcK5e773fl2rVo6hxbSO6dH2R+fOX2NKYg7PvVUBkki/EwsPDKFYsIvPxvc3vYsOGLbbECoj3ygVdLnaNQ58KFDPGxF38hIgs8Hcwf2UMf6NXX2Ji15KUdIJmHbry4jOPU7JEMf6v33ccTTrOi2/04vqa1RnU7xOif57Cnr37GfDDKAb8MAqAQf0/4YpSkQFXr0DiZJ2cjDVi+H+4q8ltlClTmp07VtK7zxf88OPoQh2rfPmyjB83BICg4CBGj57E7NkL/B4HAuSz7oIzdJ0+F50+V/3v0Olzc3Z6bB+fdzms84dOHkqf6Z2iSikFEKAnt7mhDbpSSgGkBu7oFV9pg66UUhDQFzt9pQ26UkqBKy6KaoOulFKgfehKKeUaeobuDk4OJUyelePMB35XvGUvx2Kp/PGIM6PgPOLcbB+p6b7n6AwI2qArpZQ7mLRC9gsoG9qgK6UU6Bm6Ukq5hg5bVEopl0jXUS5KKeUO2uWilFIu4YKLoq7IKQrOZUK3I87Iuat4oM8PdOo9lBFzvQm/t+xN5InPRvBgnx946T8TOHn6LABLN+7k0U+H8WCfH3j002Gs2LzLL/tQtGhRli6ZyqqVv7Imbh69PnzNL+Vmx8ns7k7Fsvv4DRr4BXv3xBG7ek7mugc63Udc7FzOnN5N3bq3+CVOlSoVmTVrNLGxc1m9eg49evwNgFKlSjJt2kjWr/+NadNGEhlZ0i/xsnLqO5wjzSkaOJzKhO7vOPH7DjFhyVpGvN2Vse8/xaJ129mdeIzew2fxUse7GP/h09xTuyY//RoDQKliYXz9YifGf/g0Hz3Zmvd+mO6X/Th79izNW3SmXtS91ItqQcsWd9OwQV2/lJ2Vk9ndnYxl9/EbNnwcbdt1vWDdho1b6Pzwcyxa5L8MQqmpabz11sfUqdOMJk3a88ILT3D99TV5/fUezJ+/hJtvvov585fw+usv+i1mBqe+wzlKN74vAcq2Bl1ErheRZiJS7KL1reyI51QmdH/H2ZFwlFrVKhJWJITgIA/1al7J3Nit7D54lHo1qwDQ6IaqzF3tnez/+qvKUy7Se0ivqVSGs+dTOXfeP7PEpaScAiAkJJjgkBDsmCvfyezuTmeSt/P4LV68nGMXfe42b45n69YdfosBkJCQSFzcegBOnkxh8+Z4KleuQLt29zJixHgARowYz/33t/BrXHDuO5wjF2QssqVBF5GXgMlAT2C9iLTP8vSndsQsrGpUKsPq+L0knTzN6XPnWbx+BwePJVO9Uhnmr4kH4NfVW0g4duIv285ZvZUbripHkRD/XArxeDysjJnNgX1rmTt3IStiYv1SblZOZnd3OpO8E8fPSVWrVqF27ZtYsSKWcuXKkJCQCHgb/XLlyhTw3tlAz9Bz9BxQzxjTAbgb+EBEXraey/EeZxHpJiIrRWRlenqKTbsWWKpXvIKnWzag+zfj6PHNeK67shwej4feT7Ri7G+xPPrpMFLOnCMkOOiC7eL3H+brib/xfhf/nSmlp6cTVb8FVa+Oon5UHW666Tq/lf2/wE3HLyIinOjogbz+em+Sk0/+5XkXzGP1FyY93eclUNk1ysVjjDkJYIzZKSJ3A+NFpCqXaNCNMYOAQeBsCrqC1vH2W+h4u/ei1jeTFlI+sjhXV7iCAS93BmDXwaMsWvfnn9YHjyXz6oBJfPRUG64sW8rv+3P8+AkW/LbEe0HRz0mBnczuXlCZ5O08fk4IDg5m9OiBjB49kcmTZwKQmHiYChXKkZCQSIUK5Th06HAB76UNdJRLjg6KSO2MH6zGvS1QBqhlU8xC6+gJ718jB46eYF7sNlo3uCFzXXq6YfD0pTzUpDYAJ06doee3P/NyxybUqVHFb/tQpkxpSpYsAUBoaCjNmzVhy5btfis/g5PZ3Z2M5dTxc8LAgf9i8+Z4vvnm+8x1U6f+SteuDwLQteuDTJnya0Htnn1c0OVi1xn6E8AFV+qMManAEyIy0I6ATmVCtyPOa4Mmc/zkGYKDPLzzaHNKhIcycu4qxvzm7YNtVqcm7RvfDMCYBbHsPpTEwGm/M3Da7wAMeOkhSpeIyNc+VKxYnqFD+hMU5MHj8TB+/BSmTZ9z+Q1zycns7k7Gsvv4DR/2LU2sz92O7TH0+ehLjh1Nol+/jyhbtjSTJ/3EmrUbaNu26+ULu4TGjevTpcsDrFu3ieXLZwDw4Yef88UX/2XkyO946qmH2b17H126dPdHtS7g1Hc4RwHcleIrsWMkgz+4tctFp89V2dHpc/MZ69y+fB/AlA8f8bnNiegz2pk3LJdcMw5dKaXyxY/DFkXkHyKyQUTWi0i0iISKyNUislxE4kVkjIgUsV5b1Po53nq+Wl6roA26UkqB3/rQRaQy8BIQZYy5GQgCHgE+A/oZY2oAx4BnrE2eAY5Z6/tZr8sTbdCVUgowqWk+Lz4IBsJEJBgIBw4A9wDjred/AjpYj9tbP2M930wkb31w2qArpRTk6gw96z0z1tItoxhjzD7gC2A33ob8OLAKSLIGhwDsBSpbjysDe6xtU63XX5GXKuhsi0opBbm6pT/rPTMXE5FSeM+6rwaSgHGALVOeXEzP0JVSCvw5Dr058Icx5pAx5jwwAbgdiLS6YACqAPusx/uAKwGs50sCR/JSBT1Dd5iTQwmT53ziSJzizd9zJI6bpTs0fDjdFP67Ie1i/HfD0G6gkYiEA6eBZsBKYD7wIDAaeBLvfFcAv1g/L7Wen2fyOJ5cG3SllALw7WLnZRljlovIeGA13hssY/F2z0wDRovIx9a6IdYmQ4DhIhIPHMU7IiZPtEFXSinw6y39xphewMV/ju8AGmTz2jPAQ/6Iqw26UkpBQM/R4itt0JVSCmxJ6OI0bdCVUgpccYbummGLbkw87K9YvX6cRtNXv+aBXoMz1x1POc3zX0XT7r0BPP9VNCdSTgPes5TPomfT7t3veOif37Np15/zh//y+1ravTeAdu8N4Jff1+a5ToU5ofeluCUh9cU8Hg8xK2YxeeJPl39xPhR8kujCP32uKxp0tyYe9les+xvX4r8vP3zBuqEzltLwhmpM+eQFGt5QjaEzlgGweL03SfUvn7zAB4+35pOR3gQHx1NOM3DKEka8+yQj332SgVOWZP4SyK3CmtD7UtyUkPpiL/V8ls2bt9lWfoaCThJtUtN9XgKVKxp0tyYe9lesetdeRYmI0AvWLYjbRrvbvLlG2t1Wi/lxWzPXt210MyLCLddUJvnUWQ4lneT39TtodGM1SkaEUSIijEY3VmPJ+rwlKC6sCb0vxU0JqbOqXLkibVo3Y+jQaFvKz6rAk0Sn52IJULY16CLSQETqW49vFJFXRaSNHbHcmnjYzlhHTqRQNrIYAGVKRnDEypCUeCyZCqVLZL6ufKniJCYlk5h0kgqlLl7/11yT/6vcmpD6qy978/Y7H5PuguQPl2PSjc9LoLKlQReRXsA3wHci8n/At0AE8LaI5Hhb4f9ikuhAICLkcXI3VUCcSEh9X5vmJCYeZnXsOr+XHZC0Dz1HD+Kdu6AJ0APoYIz5CGgJPJzTRsaYQcaYKGNMlMfje0o1tyYetjPWFSUiOGSdYR9KOknp4uEAlCtVnISjJzJfd/BYMuUii1MushgJxy5eX8wv++IGgZCQ2t8aN46iXdsWxG9dxsgR/6Vp09v56cdv/B4nYGiXS45SjTFpxphTwHZjzAkAY8xpbDgcbk08bGesu26tyZSl3jOvKUvXcXftmpnrpy5bjzGGtdv3USysKGUji9H45uos3fAHJ1JOcyLlNEs3/EHjm6v7ZV/cwI0Jqd97vy/VqkdR49pGdOn6IvPnL+HJp17ye5xA4YYuF7vGoZ8TkXCrQa+XsVJESmJDg+7WxMP+ivX2oEms3LqbpJOnafHGt3S//07+1roRbw6cxMTFa6h0RUk+f74DAHfWuobF67bT7r0BhBYJofdT9wFQMiKMbm1vp8snPwLQrd0dlIwIy1O9CnNC75y4KSF1QSnoJNEmNXAbal/ZkiRaRIoaY85ms74MUNEYc9lOObcmiXaSzrao/lf4I0n00fZ3+dzmlJ78W0BedLLlDD27xtxafxg4bEdMpZTKj1zktwhYeuu/UkpBQF/s9JU26EophZ6hK6WUa2Smby7EtEFXSin0DF0ppVxDG3QV0JwaTpg88Q1H4gAU7/gvx2I5OS7NjWN0A3Jc36WYQrfHf6ENulJKoWfoSinlGiZdz9CVUsoV0tO0QVdKKVfQLhellHIJ7XJRSimXsCmLn6NckVMUnMu47tZYdsQZuXAtD3w+mk6fjWbEb2sy10cvWkeHvtF0+mw0/aYsBWDf0RM0fHMQnb8YS+cvxvLxuN/8sg9Ovlfbti4jdvUcVsbMZtnS6bbGcrJeHo+HmBWzmDzxJ1vjvPzSc8TFzSM2di7Dh/+HokWL2hrvYiZdfF4ClSvO0DMyrrdq8yh79x5g2dLpTJk6m02b/J+p3I2x7IgTf+AIE5ZtZMQrDxASFESPQVNpcmM1DiadZMH6Pxj7emeKBAdxNPlU5jZVypRg7Oud/VElwNn3KkPzex/iyJFjtpUPztfrpZ7PsnnzNkoUL25L+QCVKlWgR4+/ccutTTlz5gyjRg3g4c7tGTZ8rG0xL+aGi6KOnaGLyDC7ynYy47obY9kRZ8fBJGpdVZ6wIiEEB3mod00l5q7bwdjfN/B0s7oUCQ4CyEx9Zwcn3ysnOVmvypUr0qZ1M4YOjbal/KyCg4MJCwslKCiI8LAw9h+wP4VfVq4+QxeRf3OJG9iMMTnmohKRXy5eBTQVkUhr2/tzt5uXll3G9Qb16/gzhKtj2RGnRsXSfDtjOUkpZygaEsTiTbu58cqy7DqUxOod+/l2+nKKBgfxj/sbc/NV5QDYdzSZh78cR7GiIfRo04C61StdJorz9boUYwwzpkdjjGHw4BF8P2SkLXGcrNdXX/bm7Xc+pnhxe/PH7t+fQL9+A9ixfQWnT59hzpzfmDNnoa0xL2ZcfqfoynyUWwXYCHyP95eCAFHAl5faSES6Ad0AJKgkuUkUrQJL9fKleLppHboPnEJYkRCuq3wFHhHS0tM5ceosw1/uxPrdibw5bDbT3utC2RIRzPzgcSIjQtm45xD/+GEGP7/5CMVCixR0VXx2d9OO7N+fQNmyVzBzxmg2b4ln8eLlBb1beXZfm+YkJh5mdew67mpym62xIiNL0q5dS2pe24ikpBOMHj2Qxx7rxKhRE2yNm5Wrhy0aY/JzBSQKeBl4D3jDGBMnIqeNMZe80mWMGQQMgtyloHMy47obY9kVp2OjG+jY6AYAvpm2jPKRxdiZmESzWtUREWpVLY9HhGMpZyhdLCyzG+bGK8tS5YqS7DqUxE1XlstzfCffKyCz7EOHjjBp8gzq169tS4PuVL0aN46iXdsWtG51D6GhRSlRojg//fiNLYmimzW7k507d3P48FEAJk2awW2Nohxt0NP9eIZu9UZ8D9yM96T2b8AWYAxQDdgJdDbGHBMRAb4G2gCngKeMMavzEveyfegiUlZEvhCR6SIyL2O51DbGmHRjTD/gaeA9EfkWGy/AOplx3Y2x7IqTccHzwLFk5q37g9Z1a9K01tXExO8DYFdiEufT0igVEcrRk6dJS/eeIu09coLdh45TpXSJfMV38r0KDw+jWLGIzMf3Nr+LDRu22BLLqXq9935fqlWPosa1jejS9UXmz19iS2MOsGf3Pho0rEtYWCgA9zS9g82b7bt4nR1jxOfFB18DM40x1wO3ApuAt4G5xpiawFzrZ4DWQE1r6QZ8l9c6+NLIjsT7W+U+4AXgSeCQL4UbY/YCD4nIfcCJvO7k5TiZcd2NseyK89qPszh+6izBHg/vdLqTEmFF6dDgenqNns8Dn48mJCiIjx69BxFh9fb9/HdmDMFBHjwivP9QE0pGhAZkvbJTvnxZxo8bAkBQcBCjR09i9uwFtsRysl5OWRETy4QJ01ixYhapqamsidvA4O/tuQaRE3+NchGRkkAT4CkAY8w54JyItAfutl72E7AAeAtoDwwzxhhgmYhEikhFY8yBXMc2lxlNLyKrjDH1RGStMeYWa12MMaZ+boPlRm66XFTB0ulz88+NH3Ynj9/5c/vyHW7jNff5/DbctGP681jX+yyDrC5jRKQ23q7jjXjPzlfh7YLeZ4yJtF4jwDFjTKSITAX6GmMWW8/NBd4yxuT6OqYvZ+jnrf8PWGfa+4HSuQ2klFKBLDd96Fmv92UjGKgL9DTGLBeRr/mzeyVjeyMifv897kuD/rH1J8RrwL+BEsA//L0jSilVkPw4bHEvsNcYk3FFfDzeBv1gRleKiFQEEq3n9wFXZtm+irUu1y57UdQYM9UYc9wYs94Y09QYU88Yc/E4c6WUKtSM8X25dDkmAdgjItdZq5rh7X75Be81SKz/J1uPfwGeEK9GwPG89J+DD2foIvID2XTxGWP+lpeASikViPw5bBHoCYwUkSLADrwj/jzAWBF5BtgFZMxzMR3vkMV4vMMWn85rUF+6XKZmeRwKdMTbj66UUq6R7sdb+o0xcXjvx7lYs2xeawC/zLB22QbdGPNz1p9FJBpY7I/gSikVKPx8hl4g8nKzT00g77fvKcc49fF0cijhib5tHIsV+c4Mx2Jdbviwv3jEuUYrvZBNMO72uVwAEJFkLuxDT8A7GF4ppVzjf+IM3Rhj3yTISikVIArX3xPZ82Uul7m+rFNKqcIsLd3j8xKoLjUfeigQDpQRkVL82SVbAqjswL4ppZRjXDB77iW7XJ4HXgEq4Z2LIKNBPwF8a+9uKaWUs4yjs8/Y41LzoX8NfC0iPY0x/3Zwn5RSynHpLuhE96UzKD0jdRyAiJQSkRft26XcK1q0KEuXTGXVyl9ZEzePXh++Zms8JzOuOxXLyYzrdtQpuG5zQp/oTegT/6RIm+cgKJgiLZ8m9Jn/I7Trh4R2/RAp650uIziqRea60Cf+SdgrAyE097lNBw38gr174ohdPSdzXalSkUyfPooNGxYxffooIiNL+qV+WQ0e9CX7964hLtaeS1nZ1eufvV5n1cpfiVkxi2nTRlKxYnm/x3Xye5WddMTnJVD50qA/Z4xJyvjBGHMMeM62PcqDs2fP0rxFZ+pF3Uu9qBa0bHE3DRvUtSVWRsb1tu26UuvWpjz8cAduuKFmoY6VkXG9UaM21KnTjKCgIB7u3N7vccCeOkmxSILrNOPMqI85M+yfIB6CrmsAwPmF4zgzog9nRvTBHNoDQOrK2Znrzi+eQPrerXDmVK7jDhs+jrbtul6w7s03ejB/3hJuuulO5s9bYkvDNGzYWO5r28Xv5WaWn029vvxqAPWi7qV+g5ZMnz6X9957xa8xnfxe5cQgPi+BypcGPciauxcAEQkCcpXoUUTuEJFXRaRFbnfQVykp3i9kSEgwwSEhtt2o4WTGdSdjOZVx3bY6eTwQHALiQUKKYFKSfNos6PoGpG5ZkaeQixcv59ixC+O0a9eC4SPGATB8xDjuv9//79eixcs5elFcf8quXsnJJzMfR4SH+f375eRnPSdpiM9LoPKlQZ8JjBGRZiLSDIgGLnkLnYisyPL4ObwXUYsDvUTk7Rw3zAePx8PKmNkc2LeWuXMXsiIm1o4w2WZcr1SpQqGOlTXj+p7dsZw4ccK2jOt21MmcTCJ15WzCnv2MsOe/wJw9TfqujQCE3N6R0Md7EXJXZwi66JJRcBGCqt1M2rZV+YqfVblyZUhI8M6KmpCQSLlyZfxWdkHr0/tNtsev4NFHO9K79xd+LdvJ71VO0nOxBCpfGvS3gHl408+9AKwDwi6zTUiWx92Ae40xvYEWQI5/K4pINxFZKSIr09NTfNi1P6WnpxNVvwVVr46iflQdbrrpustvpIALM65fVbUu4RHhPPZYp4LeLd8VDSfomtqcHvIOpwe9ASFFCLqhIecWT+DMjx9wZtQnSGgEwfVbXbBZUPVbSN8Xn6fuFl85dUu/Ez7s9TnX1GhAdPREXuye5wkBA9b/RINujEkHluPNUt0AuAdvwtNLlmtdPL0Cb5q7Q1ZZKUDqJWINMsZEGWOiPJ4IH6twoePHT7DgtyW0bHF3nra/HCczyTsVK2vG9dTU1MyM63awo05BV92AOXEYTp+E9DTStsXiqXgNpBz3viAtldQNSwiqcPWF2+WjuyUniYmHqVDBO9VRhQrlOHToiF/LDwTRoyfSsWNrv5bp5PcqJ67uQxeRa0Wkl4hsxpupaDeAleTicuPQS+Idu74SKG1l50BEimHDnFFlypSmZElvhvjQ0FCaN2vCli3b/R0GcDaTvFOxnMy4bkedTPJRPBWqQ7D30k7QVddjjiZAxJ8jTIJq1CH9cJYkMEXCCKpyLWnxcfmKfbEpU3/l8a4PAfB414eYMsWez4bTatT485dhu3Yt/f79cvJ7lZN08X0JVJe6sWgzsAhoa4yJBxARn1LPGWOq5fBUOt751P2qYsXyDB3Sn6AgDx6Ph/HjpzBt+pzLb5gHTmZcdyqWkxnX7ahTesIfpG1bRWjX9yE9nfTE3aSuW0jRji8j4d5ziPRDezg3Z0TmNkE16pC2cwOknstz3OHDvqVJk9soU6Y0O7bH0OejL/nXv75l1KgBPPX0I+zevZfHHuuer7plZ8Tw/3CXFXfnjpX07vMFP/w42m/lZ1ev1q3u4dprq5Oebti9ey89/v6O3+KBs9+rnATycERfSU59fCLSAXgEuB3vhdHRwPfGmKuz3cDPgotUdk/nYwFx6uPp5Bvl1ulznZpq1q3T56ae25fvik2o8JjPO9wpYVRAtv45drkYYyYZYx4Brgfm450GoJyIfGfn8EOllCoI6SI+L4HKl4uiKcaYUcaYdnizUcei86ErpVzG5GIJVLmaB9IYc8waifKXvHhKKVWYuWHYYl5S0CmllOsE8ugVX2mDrpRSENC39PtKG3SllELP0FWAC+SLN3lV4u3pjsVKHtPTsVjFH3Ym5YCTQwkLm0DuG/eVNuhKKYU7ToC0QVdKKbTLRSmlXEO7XJRSyiXS9AxdKaXcwQ1n6Lm6U1QppdzK33eKikiQiMSKyFTr56tFZLmIxIvIGBEpYq0vav0cbz1fLa91cE2Dbncm9AxVqlRizuxxrF0znzVx8+j592dsjedUJnSn4hQtWpSlS6ayauWvrImbR68PX7Mtlh2fiZGLN/BAv4l0+moiIxZvuOC5YQvXU/vtHziWcgaA5DPneOnHOXTuP4lOX01k0kr/zTHvxPvl5HsFzn0Gc2LDXC4vc2EyoM+AfsaYGsAxIKPxeAY4Zq3vZ70uT1zToNudCT1Damoqb7zZm1tubcrtd7Sje/enbMtO7lQmdCczrp89e5bmLTpTL+pe6kW1oGWLu2nYoK4tsfz9mYhPOMaEmK2M6NGOsS+3Z9HmPew+fAKAhKSTLN22j4qRf2baGrN0E9XLl2TsKx34vltrvpq2gvOpafneD6feLyffKyc/gznxZ4ILEakC3Ad8b/0seLO9jbde8hPQwXrc3voZ6/lm1utzzZYGXUQaikgJ63GYiPQWkSki8pmIlLzc9nlhdyb0DAkJicTGrQfg5MkUNm/eRmWbktk6lQnd6YzrKSneHJ4hIcEEh4TYlnfT35+JHYlJ1LqyLGFFggkO8lDv6grM3bALgC+mruCV1vXJOgu9IKScTcUYw+lz5ykZXpQgT/6/ck6+X069V05/BrOTmy6XrPmPraXbRcX1B97kzx6aK4AkY0xGCs69QGXrcWVgD4D1/HHr9blm1xn6UCAj8+7XeFPSfWat+8GmmI6rWrUKtW+9meUrYm0p36lM6E5nXPd4PKyMmc2BfWuZO3chK2LsOX7+VqNCKVbvPEhSyhlOn0tl8Za9HExKYf6GXZQtEc51lUpf8PpHGt/AH4lJ3PvpGB7sP4k32jXE48n/UAon3y+n3iunP4PZScvFkjX/sbUMyihHRNoCicaYVY5WAPtGuXiy/CaKMsZk/J22WETictrI+i3XDUCCSpLXRNFOiIgIZ+yYwbz6ei+Sk08W9O4UKunp6UTVb0HJkiX4edwQbrrpOjZs2FLQu3VZ1ctF8vRdteg+dDZhIcFcV7E059LSGLJgLd8989ezyd+37uO6iqUZ/Fwr9hxJ5oUhs6hbrTzFQosUwN7nTWF9r/LCjzcW3Q7cLyJtgFCgBN4T20gRCbbaxipARpLbfcCVwF4RCcZ7Apyn7OJ2naGvF5GnrcdrRCQKvImngfM5bZT1t14gN+bBwcGMGzOY6OiJTJpkX5oypzKhF1TG9ePHT7DgtyW0bHG37bH8pWP9a4nueT9DX2hD8bCiXFMukn1HT9K5/2Ra9x1H4okUHv3mFw4nn2Lyym00u7kqIsJVZUpQuVQx/jh0PN/7UBDvl93vVUF9BrPy1ygXY8w7xpgqVm7lR4B5xpgueDO/PWi97ElgsvX4F+tnrOfnmTz2bdnVoD8L3CUi24EbgaUisgMYbD1XqA0e9CWbNsfT/+tBl39xPjiVCd3JjOtlypSmZMkSAISGhtK8WRO/Z5C309GTpwE4kHSSeRt20a5eDeZ/8Cgz3n6IGW8/RLkSEUS/dD9liodTMTKC5fEHADiSfJqdh09QpXTxfO+DU++Xk++Vk5/BnDiQsegt4FURicfbRz7EWj8EuMJa/yrwdl4D2NLlYow5DjxlXRi92oqz1xhz0I54YH8m9Ay3N67P410fZO26jayM8X7gPvigLzNmzvN7LKcyoTuZcb1ixfIMHdKfoCAPHo+H8eOnMG36HFti2fGZeG3EfI6fOkOwx8M77RtRIqxojq99rlltPhy3iAf7TcQAr7SOolREaL7ig3Pvl5PvlZOfwZyk2zA9lzFmAbDAerwDaJDNa84AD/kjnth11Tq/gotUDswdU/8z3Dh9rlulntuX7x7wPlW7+NzmfLhrZEBOFKC3/iulFO649V8bdKWUQqfPVUop17CjD91p2qArpRSasUgppVxD+9CVUsol0lxwjq4NusOCPUGOxUpNz//Mfv/LnBxKmDyjlyNxSrbp40icwkjP0JVSyiX0oqhSSrlE4W/OtUFXSilAu1yUUso19KKoUkq5hBv60F2TU9SpBLN2J4keOPBf7N69mlWrfs1cd8stN/Lbb5NYvnwGS5ZMJSrqVr/GBGcTAjv1XjmVODyDv+s1ct5qHvjoRzp99CMj5nmT32zek8jjn4+i86fDeKzvCNbtPHDBNut3JlDv71/x6+q8z1Q4aOAX7N0TR+zqP2dWfKDTfcTFzuXM6d3UrXtLnsu+lL///RliV88hLnYuPXvam3w9Ow5Mn2s7VzToTiaYtTtJ9PDh47j//icuWPfpp+/yySf9adiwNX36fMmnn77rt3gZnEoI7OR75VTicPB/veL3H2bCkrWMeKsLY999gkXrdrA78Rj9Jy7k+ftuY+y7T9C9bWP6T1yYuU1aejpfT1pIoxuq5asuw4aPo227rhes27BxC50ffo5Fi5bnq+yc3HTjdTzzt0dpfHtb6kW1oE2b5lxzTTVbYuUkHePzEqhc0aA7mWDW7iTRixev4NhFiY2NMZQo4U2MULJkcQ4csGdaeScSAjv5XjmVOBz8X68dCUeoVa0iYUVCvAmpa1Zhbtw2RCDl9FkATp4+S9mSxTK3iV4QS7M6NSldPDxfdVm8ePlfPoObN8ezdeuOfJV7KddfX4MVK+I4ffoMaWlpLFq4jA4dWtsWLzv+ylhUkGxp0EXkJRG50o6ys1NQCWbtThKd4fXXe/N///cu8fHL+L//e58PPvjMljhOJAQOhGTAdvB3vWpULMPq7ftIOnma0+fOs3jDHxw8lswbDzal38SFtHx3IF9NWMhL7e8E4GBSMvPj4ul8Z+38VqVAbNi4hTvuaEDp0pGEhYXSqtU9VMmSks4JJhf/ApVdZ+gfActFZJGIvCgiZX3ZSES6ichKEVmZnp5i0675h5NJort1e5w33uhDjRqNePPNPgwY8C9b4mQkBK56dRT1o+pw003X2RJHXV71ilfw9L316f7v8fT49meuq1IOj8fDuEVreP3Bu5n16fO8/uDd9B4xC4B/jVvAyx3vxOMpnHPAbt4cz7+++C/Tp41i6pQRrFm7gbQ0Z+90TsP4vAQquxr0HXizWn8E1AM2ishMEXlSRHJMqpjXJNFOJ5h1Kkl0hq5dH8iM8/PP9lwUzcrOhMCBkAzYDnbUq+PttYh+53GGvvoIxcOLUrVcKaYs20Cz2t6++RZ1r2X9Lm+MjbsTeGvINFq/P5g5sVv5dPQc5sVty1d8p/3442ga3daGZs0fJOnYcbZts6+LJzva5ZIzY4xJN8bMNsY8A1QC/gu0wtvY+5XTCWadShKd4cCBgzRp0giApk1vJz5+p99jOJUQOBCSAdvBjnodTfZe0zhw9ATz4rbRuv71lC1ZjJXb9gKwYsturiobCcD0j55jxsfepXmda3n3kebcU9uei812KVv2CgCuvLISHTq0ZvToSY7GTzfG5yVQ2TUO/YK/+4wx54FfgF9EJH9XbLLhZIJZu5NEDxv2b+688zbKlClFfPxyPv74K1588W2++OKfBAcHcebMWXr0yHNS8Bw5lRDYyffKqcThYE+9Xhv0C8dTThMcFMQ7DzejRHgoH3a5l8/HzSct3VAkJIgPurTwUw3+NHzYtzSxjtuO7TH0+ehLjh1Nol+/jyhbtjSTJ/3EmrUbaNu26+ULy4UxowdxxRWlOH8+lZdefo/jx0/4tfzLCdxm2ne2JIkWkWuNMfn6NLs1SbTOtqiyo7Mt5s+5s3vzffHgsaodfW5zRu2aGJAXK2w5Q89vY66UUk4L5NErvtJb/5VSCkjVBl0ppdxBz9CVUsolAnk4oq+0QVdKKbBlqgunaYOulFK4Y/pcbdAdpkMJVXaKt+7tSJzkyW85EgegeHt75hyySyDf0u8rbdCVUgp3nKG7YvpcpZTKL2OMz8uliMiVIjJfRDaKyAYRedlaX1pEfhWRbdb/paz1IiLfiEi8iKwVkTwnItAGXSml8OvkXKnAa8aYG4FGQA8RuRF4G5hrjKkJzLV+BmgN1LSWbsB3ea2DNuhKKYX/5kM3xhwwxqy2HicDm4DKQHvgJ+tlPwEdrMftgWHGaxkQKSIV81IHbdCVUorcpaDLmrvBWrplV6aIVAPqAMuB8saYjCSwCUB563FlYE+WzfZa63JNL4oqpRSQZny/tcgYMwi45PzZIlIM+Bl4xRhzQuTP+byMMUZE/H4V1jVn6G7MJF+lSiXmzB7H2jXzWRM3j55/ty8TulPHz8k6gXP1cjKWHZ/Bkb+t4YG+0XTqO4oRC9Zkro9euJYOn46kU99R9PvldwCmrdxC589HZy51/vEfNu89lO99cPK7lR1/pqATkRC8jflIY8wEa/XBjK4U6/9Ea/0+IGvKzirWulxzRYPu1kzyqampvPFmb265tSm339GO7t2fsqVeTh4/p+oEztarMH8G4w8cYcLSjYx49UHGvvEIizbuZPehJGK27WXB+j8Y++YjTHj7MZ5sWhuA+6KuY+ybjzD2zUf4pOu9VC5dguur+JRl8pKc/G5lx18JLsR7Kj4E2GSM+SrLU78AT1qPnwQmZ1n/hDXapRFwPEvXTK7YlSS6iIg8ISLNrZ8fE5FvRaSH9ZvLr9yaST4hIZHYuPUAnDyZwubN26hsQ0JlJ4+fU3UCZ+tVmD+DOw4eo1bV8oQVCSE4yEO9ayoxd+0Oxi5Zz9PN6lIk2DuHf+nif81NM2P1VlrW9c8vLie/W9kxuVgu43bgceAeEYmzljZAX+BeEdkGNLd+BpiON5NbPDAYeDGvdbCrD/0Hq+xwEXkSKAZMAJoBDfjzt5RfZJdxvUH9Ov4MUeCqVq1C7VtvZvmKWL+XXVDHz846gbP1KsyfwRoVSvPttGUkpZyhaEgQizfu4saryrErMYnVO/bz7bRlFA0J5h/tG3PzVeUv2HZ2bDz9n21TQHvuX/66scgYs5iLsrZl0Syb1xvAL310djXotYwxt4hIMN6+oErGmDQRGQGsyWkj60pxNwAJKkluEkW7WUREOGPHDObV13uRnHyyoHfHL9xYp8KqeoXSPN2sLt2/+4WwIsFcV7kMHhHS0g0nTp1l+D8eZP3uRN78cRbTPnicjIt763YmEFokmBoVryjgGviHG+4UtatB94hIESACCAdKAkeBokCOXS5ZrxznJgWdWzPJAwQHBzNuzGCioycyadIMW2I4ffycqBM4W6/C/hns2OhGOja6EYBvpi6lfGQxdiYm0eyW6ogItaqWxyPCsZQzlC4WBsDM2Hha+am7JRDkZpRLoLLrougQYDMQB7wHjBORwUAM4PcsvW7NJA/eK/+bNsfT/+tLjpDKF6ePnxN1AmfrVdg/g0eTTwFw4Fgy89buoHXda2la62pitnkHW+xKTOJ8WjqlIkIBSE83zI6Lp1Ud9zTo/hzlUlDsyinaT0TGWI/3i8gwvBcBBhtjVvg7nlszyd/euD6Pd32Qtes2sjLG2zh88EFfZsyc59c4Th4/p+oEztarsH8GX/thJsdTzhAc5OGdB5tQIrwoHRreQK/oeTzQN5qQYA8fPdYss7tl1fb9VIgsRpUyJf1RJcDZ71Z23DAfugRqJXLT5aKU8o1bp89NPbcvp4uQPqtb8Q6f25zVBxbnO54d9E5RpZTCHWfo2qArpRSQ5oKsotqgK6UUXPYO0MJAG3SllIKAHr3iK23QlVIKPUNXSinX0DN0pch50orCzsmvt1PHsFTHLxyKBMkT33Aslj/oGbpSSrmEG2791wZdKaXQLhellHINo2foSinlDjp9rlJKuYTe+q+UUi7hhjN0VySJ1kzy+edUxvVrr72GlTGzM5cjhzfzUs9nbYv38kvPERc3j9jYuQwf/h+KFi1qSxynM9Zv27qM2NVzWBkzm2VLp/ut3CpVKjJr1mhiY+eyevUcevT4GwCdOt3H6tVzOHVqJ3Xr3pKvGCMXruWBz0fT6bPRjPjtzwRm0YvW0aFvNJ0+G02/KUsv2ObAsWRue3swP82Py1fsS0lLT/d5CVSuOEPPyCQfG7eeYsUiWLF8JnPmLmTTpm1+j5WR3b1Vm0fZu/cAy5ZOZ8rU2YU+1rBhY/nvf3/ghx++9nvZWW3dup2o+i0Ab/127VzFpMn2ZC2qVKkCPXr8jVtubcqZM2cYNWoAD3duz7DhY/0ey6njl1Xzex/iyJFjfi0zNTWNt976mDjru7R06TTmzl3Ehg1bePjhbvznP/+Xr/LjDxxhwrKNjHjlAUKCgugxaCpNbqzGwaSTLFj/B2Nf70yR4KDMhBsZvpz8O7ffcFW+Yl+OjnK5BBGpDnQCrgTSgK3AKGPMCX/HSkhIJCEhEbgwk7wdDV/W7O5AZnb3wh5r0eLlVK1axe/lXso999zBjh272L17n20xgoODCQsL5fz584SHhbH/gD1p4Qri+Nnhr9+leCpXrsDcuYv8Uv6Og0nUuqo8YUW8mSjrXVOJuet2sHHPIZ5uVpciwUEAlC4enrnNvHV/UKl08cxt7OKGPnRbulxE5CVgABAK1MebS/RKYJmI3G1HzAwFkUm+UqUKhT5WQXi4c3vGjJlkW/n79yfQr98AdmxfwZ7dsZw4cYI5cxbaFs9JxhhmTI9m+bIZPPtMF1tiVK1ahdq1b2KFH79LNSqWZvUfB0hKOcPpc+dZvGk3B5NOsutQEqt37Kdr/5955ttJrN/t/aVy6ux5fpwXywst6/ttH3KSjvF5CVR29aE/B7Q2xnyMN/XcTcaY94BWQL+cNhKRbiKyUkRWpqen5DqoZpIvPEJCQmjbtgXjf55qW4zIyJK0a9eSmtc24qqqdQmPCOexxzrZFs9JdzftSIOGrWjbrivduz/FHXc09Gv5ERHhREcP5PXXe/v1u1S9fCmeblqH7gOn0GPQNK6rfAUeEdLS0zlx6izDX+7EK+1u481hszHGMGBWDF3uuoXwovaenYP3l6SvS6Cysw89GG9XS1GgGIAxZreI5PjOGGMGAYMg9ynoNJN84dKqVVNiY9eRmHjYthjNmt3Jzp27OXz4KACTJs3gtkZRjBo1wbaYTsn4HBw6dIRJk2dQv35tFi9e7peyg4ODGT16IKNHT2Ty5Jl+KTOrjo1uoGOjGwD4ZtoyykcWY2diEs1qVUdEqFW1PB4RjqWcYd2ug/y6Zgf9pywj+fRZPCIUDQ7ikTtr+X2/Avlip6/satC/B2JEZDlwJ/AZgIiUBY7aEbAgMsnv25dA587tefwJe0afOBnLaQ8/3MHW7haAPbv30aBhXcLCQjl9+gz3NL2DVavWXH7DABceHobH4+HkyRTCw8O4t/ldfPxJjn/45trAgf9i8+Z4vvnme7+VmdXR5FOULh7OgWPJzFv3B8Ne7oRHhJj4fdSvWZldiUmcT0ujVEQoP/TsmLnddzNjCC8aYktjDu4YtmhLg26M+VpE5gA3AF8aYzZb6w8BTfwdTzPJ55+TGdfDw8No3qwJL75ob8LiFTGxTJgwjRUrZpGamsqauA0M/n6kLbGcPH7ly5dl/LghAAQFBzF69CRmz17gl7IbN65Ply4PsG7dJpYv9/6l++GHn1O0aBG++qoPZcuWZuLEH1i7diPt2j2epxiv/TiL46fOEuzx8E6nOykRVpQODa6n1+j5PPD5aEKCgvjo0XsQcXYez0DuSvGVBGolctvlogqOTp+bf04dwyBPkEOR4NjPrzoWK+y+V/J9CIuFX+3zW37y1B8B+bF3xTh0pZTKLx2HrpRSLqEJLpRSyiXSXTB9rivmclFKqfzy5zh0EWklIltEJF5E3nZg9wE9Q1dKKcB/o1xEJAj4D3AvsBfvEO5fjDEb/RLgEvQMXSml8I5q8nW5jAZAvDFmhzHmHDAaaG/LTl8kYM/QU8/ty9OwIBHpZt1xaiun4miswhXLjXVyc6ysctPmiEg3oFuWVYOy7HNlYE+W5/YC/p2bIQduPEPvdvmXFKo4GqtwxXJjndwcK0+MMYOMMVFZFsd/AWXHjQ26UkoVpH14Z5fNUMVaZztt0JVSyr9igJoicrWIFAEeAX5xInDA9qHng1N/+jj5J5bGKjyx3FgnN8fyO2NMqoj8HZgFBAFDjTEbnIgdsHO5KKWUyh3tclFKKZfQBl0ppVzCNQ26U7faishQEUkUkfV2xcgS60oRmS8iG0Vkg4i8bGOsUBFZISJrrFi97YplxQsSkVgRsS8HnTfOThFZJyJxIrLS5liRIjJeRDaLyCYRuc2mONdZ9clYTojIKzbF+of1eVgvItEiEmpHHCvWy1acDXbVx/VyM39BoC54LzxsB6oDRYA1wI02xWoC1AXWO1CvikBd63FxYKuN9RKgmPU4BFgONLKxbq8Co4CpNh/DnUAZu98rK9ZPwLPW4yJApAMxg4AEoKoNZVcG/gDCrJ/HAk/ZVI+bgfVAON7BGnOAGk68b25a3HKG7tittsaYhdiURi+bWAeMMautx8nAJrxfMjtiGWNMRjbgEGux5Yq5iFQB7sObqtAVRKQk3l/2QwCMMeeMMUkOhG4GbDfG7LKp/GAgTESC8Ta2+22KcwOw3BhzyhiTCvwGuCOjt4Pc0qBnd6utLQ1fQRGRakAdvGfOdsUIEpE4IBH41RhjV6z+wJuAE/OVGmC2iKyybte2y9XAIeAHqyvpexGJsDFehkeAaDsKNsbsA74AdgMHgOPGmNl2xMJ7dn6niFwhIuFAGy68OUf5wC0NuquJSDHgZ+AVY8wJu+IYY9KMMbXx3tnWQERu9ncMEWkLJBpjVvm77BzcYYypC7QGeoiI33PaWoLxdsV9Z4ypA6QAtk6bat20cj8wzqbyS+H9S/dqoBIQISJd7YhljNmEN5n8bGAmEAek2RHLzdzSoBfYrbZ2E5EQvI35SGPMBCdiWl0F84FWNhR/O3C/iOzE2zV2j4iMsCEOkHmWiTEmEZiIt3vODnuBvVn+qhmPt4G3U2tgtTHmoE3lNwf+MMYcMsacByYAjW2KhTFmiDGmnjGmCXAM7zUjlQtuadAL7FZbO4k37fkQYJMx5iubY5UVkUjrcRjeuZw3+zuOMeYdY0wVY0w1vO/TPGOMLWd9IhIhIsUzHgMt8P5p73fGmARgj4hcZ61qBtg9//Wj2NTdYtkNNBKRcOuz2AzvdRxbiEg56/+r8Pafj7Irllu54tZ/4+CttiISDdwNlBGRvUAvY8wQO2LhPZt9HFhn9W0DvGuMmW5DrIrAT9bk/B5grDHG1iGFDigPTPS2RQQDo4wxM22M1xMYaZ1U7ACetiuQ9QvqXuB5u2IYY5aLyHhgNZAKxGLvbfk/i8gVwHmgh0MXlV1Fb/1XSimXcEuXi1JK/c/TBl0ppVxCG3SllHIJbdCVUsoltEFXSimX0AZd2UJE0qyZANeLyDjrdu68lvWjiDxoPf5eRG68xGvvFpFc3/xizcpYJq/7qFQg0AZd2eW0Maa2MeZm4BzwQtYnrcmecs0Y86wx5lI37NyNjXczKhXItEFXTlgE1LDOnheJyC/ARmsysH+JSIyIrBWR58F7h6yIfGvNbz8HKJdRkIgsEJEo63ErEVltzeE+15rA7AXgH9ZfB3dad8D+bMWIEZHbrW2vEJHZ1tzb3+OdPlipQs0Vd4qqwGWdibfGO+ESeOc3udkY84c1++FxY0x9ESkKLBGR2XhnlbwOuBHv3Z4bgaEXlVsWGAw0scoqbYw5KiIDgJPGmC+s140C+hljFlu3lM/CO1VrL2CxMaaPiNwHPGPrgVDKAdqgK7uEZZmuYBHeOWkaAyuMMX9Y61sAt2T0jwMlgZp45xWPNsakAftFZF425TcCFmaUZYzJaY765sCN1u3/ACWs2SubYM23bYyZJiLH8lZNpQKHNujKLqetqXgzWY1qStZVQE9jzKyLXtfGj/vhwZt56Uw2+6KUq2gfuipIs4Du1hTBiMi11qRTC4GHrT72ikDTbLZdBjQRkautbUtb65PxpuvLMBvvpFlYr6ttPVwIPGataw2U8lellCoo2qCrgvQ93v7x1eJNuj0Q71+NE4Ft1nPDgKUXb2iMOQR0AyaIyBpgjPXUFKBjxkVR4CUgyrroupE/R9v0xvsLYQPerpfdNtVRKcfobItKKeUSeoaulFIuoQ26Ukq5hDboSinlEtqgK6WUS2iDrpRSLqENulJKuYQ26Eop5RL/Dy6bD1rXodoLAAAAAElFTkSuQmCC",
      "text/plain": [
       "<Figure size 432x288 with 2 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Confusion Matrix\n",
    "\n",
    "# Generates output predictions for the input samples.\n",
    "test_predictions = model.predict(x=x_test)\n",
    "\n",
    "# Returns the indices of the maximum values along an axis.\n",
    "test_predictions = np.argmax(test_predictions,axis=1) # the prediction outputs 10 values, we take the index number of the highest value, which is the prediction of the model\n",
    "\n",
    "# generate confusion matrix\n",
    "confusion_matrix = tf.math.confusion_matrix(labels=y_test,predictions=test_predictions)\n",
    "\n",
    "# plot confusion matrix\n",
    "import seaborn as sns\n",
    "import matplotlib.pyplot as plt\n",
    "h = sns.heatmap(confusion_matrix,annot=True,fmt='d')\n",
    "h.set(xlabel='Predicted', ylabel='Actual')"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "collapsed_sections": [],
   "name": "digits-recognizer.ipynb",
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
